package cn.zxinrun.wps.util;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
import cn.zxinrun.core.util.StringUtils;
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.deepoove.poi.config.ConfigureBuilder;
import com.deepoove.poi.plugin.markdown.MarkdownRenderData;
import com.deepoove.poi.plugin.markdown.MarkdownRenderPolicy;
import com.deepoove.poi.plugin.markdown.MarkdownStyle;
import com.deepoove.poi.plugin.table.LoopRowTableRenderPolicy;
import com.deepoove.poi.policy.RenderPolicy;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.util.TriConsumer;
import org.ddr.poi.html.HtmlRenderPolicy;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Map;

/**
 * Word 文档工具类
 * @author Mr.Zhang
 * @since 1.0
 **/
@Slf4j
public class WordUtils {

    /**
     * 生成 Word 文件
     * @param srcPath  源 Word 模板文件路径，不能为空
     * @param destPath 生成的目标 Word 文件路径，不能为空
     * @param params   模板中需要渲染的数据参数
     * @return 包含生成文档信息（如总页数）的 Map
     * @throws IllegalArgumentException 如果源文件路径或目标文件路径为空
     */
    public static Map<String, Object> generateWord(String srcPath, String destPath, Map<String, Object> params) {
        return generateWord(srcPath, destPath, params, null, null);
    }

    /**
     * 生成 Word 文件
     * <pre>
     *      功能说明：
     *      1. 校验输入参数，初始化日志和结果容器；
     *      2. 构建模板渲染配置，注册内置和外部插件；
     *      3. 根据参数类型动态绑定不同的渲染策略（如 Markdown、HTML、表格、分页符等）；
     *      4. 渲染模板并输出到目标文件；
     *      5. 获取生成 Word 文档的总页数，写入结果 Map；
     *      6. 捕获并记录 IO 异常。
     * </pre>
     * @param srcPath        源 Word 模板文件路径，不能为空
     * @param destPath       生成的目标 Word 文件路径，不能为空
     * @param params         模板中需要渲染的数据参数
     * @param plugins        自定义渲染策略插件，按需扩展渲染能力。如：{'#': new CustomRenderPolicy()}
     * @param applyProcessor 自定义处理器，用于对参数进行额外处理
     * @return 包含生成文档信息（如总页数）的 Map
     * @throws IllegalArgumentException 如果源文件路径或目标文件路径为空
     */
    public static Map<String, Object> generateWord(String srcPath, String destPath, Map<String, Object> params,
                                                   Map<Character, RenderPolicy> plugins, TriConsumer<String, Object, ConfigureBuilder> applyProcessor) {
        if (StringUtils.isBlank(srcPath) || StringUtils.isBlank(destPath))
            throw new IllegalArgumentException("源文件路径或目标文件路径不能为空");
        log.info("[WORD工具]生成WORD文件, srcPath: {}, destPath: {}, params: {}", srcPath, destPath, params);
        Dict wordMaps = Dict.create();

        try (InputStream is = Files.newInputStream(Paths.get(srcPath)); OutputStream os = Files.newOutputStream(Paths.get(destPath))) {
            ConfigureBuilder builder = Configure.builder();
            builder.buildGramer("#", "#");
            // 内置插件
            builder.addPlugin('%', new HtmlRenderPolicy());// html 解析器
            builder.addPlugin('&', new MarkdownRenderPolicy());// markdown 解析器
            // 外部插件
            if (!CollectionUtil.isEmpty(plugins)) plugins.forEach(builder::addPlugin);

            // 渲染参数到对应的插件上
            if (!CollectionUtil.isEmpty(params)) {
                params.forEach((k, v) -> {
                    if (k.endsWith("MDX")) {
                        // 解析 markdown
                        MarkdownRenderData markdownRenderData = new MarkdownRenderData();
                        markdownRenderData.setMarkdown((String) v);
                        markdownRenderData.setStyle(MarkdownStyle.newStyle());
                        params.replace(k, markdownRenderData);
                    } else if (k.endsWith("HTML")) {
                        // 解析 html
                        builder.bind(k, new HtmlRenderPolicy());
                    } else if (k.endsWith("TB")) {
                        // 解析表格
                        LoopRowTableRenderPolicy policy = new LoopRowTableRenderPolicy(true);
                        builder.bind(k, policy);
                    } else if (applyProcessor != null) {
                        applyProcessor.accept(k, v, builder);
                    }
                });
            }

            XWPFTemplate template = XWPFTemplate.compile(is, builder.build()).render(params);
            template.write(os);
            // 获取生成的 Word 文档总页数，以下这种方式获取到的总页数是不正确的
            wordMaps.put("pages", template.getXWPFDocument().getProperties().getExtendedProperties().getUnderlyingProperties().getPages());
        } catch (IOException ex) {
            log.error("[WORD工具]生成文件出错: " + ex);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return wordMaps;
    }

}
